package org.mmtk.plan.scale.metrix;

import org.mmtk.plan.Plan;
import org.mmtk.plan.scale.Scale;
import org.mmtk.policy.Space;
import org.mmtk.utility.Log;
import org.mmtk.vm.VM;
import org.vmmagic.pragma.Inline;
import org.vmmagic.pragma.Uninterruptible;
import org.vmmagic.unboxed.ObjectReference;

@Uninterruptible
public class ClosureCounts {
	// the number of processors we are simulating
	protected final static int[] procs = { 1, 2, 4, 8, 16, 32, 64, 128, 256,
			512, 1024 };
	protected final static int POINTS = procs.length;

	private String name;
	// object counters
	private ObjectReference lastPopped;
	protected long popped;
	protected long pushed;
	protected long iPushed;
	protected long msPopped;
	protected long msPushed;
	protected long narrow;

	@Inline
	private void initObjectCounters() {
		this.lastPopped = null;
		this.iPushed = 0;
		this.popped = 0;
		this.pushed = 0;
		this.msPopped = 0;
		this.narrow = 0;
		this.msPushed = 0;
	}

	@Inline
	public void dumpObjectCounters(String message, boolean full) {
		Log.write(message);
		Log.write(", name=");
		Log.write(name);
		Log.write(" Pushed: ");
		Log.write(this.pushed);
		Log.write(" Popped: ");
		Log.write(this.popped);
		Log.write(" MsPushed: ");
		Log.write(this.msPushed);
		Log.write(" MsPopped: ");
		Log.write(this.msPopped);
		Log.write(" Narrow: ");
		Log.write(this.narrow);
		Log.write(" Inv: ");
		Log.write(this.iPushed);
		
		if (full) {
			Log.write(": Last popped: ");
			if (this.lastPopped == null) {
				Log.write(" NOT SET ");
			} else {
				Space space = Space.getSpaceForObject(this.lastPopped);
				if (space == Scale.scaleSpace) {
					Log.write(" Myms space ");
				} else if (space == Plan.loSpace) {
					Log.write(" loSpace ");
				} else if (space == Plan.nonMovingSpace) {
					Log.write(" nonMovingSpace ");
				} else if (Plan.USE_CODE_SPACE && space == Plan.smallCodeSpace) {
					Log.write(" smallCodeSpace ");
				} else if (Plan.USE_CODE_SPACE && space == Plan.largeCodeSpace) {
					Log.write(" largeCodeSpace ");
				} else if (space == null) {
					if (VM.VERIFY_ASSERTIONS) {
						Log.write("space failure: ");
						Log.writeln(this.lastPopped);
					}
				}
			}
			Log.flush();
			VM.objectModel.dumpObject(this.lastPopped);
		} else {
			Log.writeln("");
		}
		Log.flush();
	}

	public ClosureCounts(String name) {
		this.name = name;
		initObjectCounters();
	}

	public String getName() {
		return this.name;
	}

	@Inline
	public void init() {
		initObjectCounters();
	}

	public void endClosure() {
		// if (Metrix.PILOT_VERBOSE) {
		// this.dumpObjectCounters();
		// }
	}

	public void addPopped(ObjectReference ref) {
		this.popped++;
		this.lastPopped = ref;
	}

	public long getMsPushed() {
		return this.msPushed;
	}

	public long getPushed() {
		return this.pushed;
	}

	public long getIPushed() {
		return this.iPushed;
	}

	public void addMsPushed() {
		this.msPushed++;
	}

	public void addPushed() {
		this.pushed++;
	}

	public void addIPushed() {
		this.iPushed++;
	}

	public long getMsPopped() {
		return this.msPopped;
	}

	public long getPopped() {
		return this.popped;
	}

	/*
	 * Objects is popped from the stack We need to note how much work is
	 * available at the moment
	 */
	public void addMsPopped() {
		this.msPopped++;
	}

	public long getNarrow() {
		return this.narrow;
	}

	public void addNarrow() {
		this.narrow++;
	}

	public void addDepth(long objects) {
	}

	public int getDepth() {
		return 0;
	}

	public long getTotalCount() {
		return 0;
	}

	public long getMinCount() {
		return 0;
	}

	public long getMaxCount() {
		return 0;
	}

	public void addPushed(long pushed) {
		this.pushed += pushed;
	}

	public void addMsPushed(long msPushed) {
		this.msPushed += msPushed;
	}
	
	public void setPushed(long pushed) {
		this.pushed = pushed;
	}

	public void setMsPushed(long msPushed) {
		this.msPushed = msPushed;
	}
	
	public void addWork(long objects) {
		//nothing here
	}
}
